home *** CD-ROM | disk | FTP | other *** search
- #ifndef DESK_VIEW_H
- #include "DesktopView.h"
- #endif
- #include <stdio.h>
- #include "Sparks.h"
-
- // The high-speed timer thread.
- long MyThread( void * );
-
- // Used to kill the nasty thread when the program exits
- thread_id ThreadId;
-
- // An arbitrary number of sparks.
- const int kSparkCount = 500;
-
- // Artificial gravity strength
- const float kNormalGravity = 1.3; // Sparks fall over time
- const float kNoGravity = 0.0; // Sparks go straight out
- const float kNegativeGravity = -1.3; // Sparks float up
-
- // How long should the little buggers live?
- const int kLifeLength = 25;
-
- // Are they wide and fast? ( SCSI? )
- const float kMaximumHorizontal = 15.0;
- const float kMaximumVertical = 15.0;
-
- // How often should the drawing function be called?
- const int kTimeTwixtCalls = 75;
-
- // Scale the pixel toss.
- const float kScalingFactor = 0.30;
-
- // Used to send messages from the timer thread to the view.
- static DesktopView *pView = NULL;
-
- DesktopView::DesktopView(BRect rect, char *name)
- : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW )
- {
- m_pBitmap = NULL;
- m_pView = NULL;
- m_ScreenRect = Bounds();
-
- m_pSparks = new BSpark[ kSparkCount ];
-
- // Kill those pesky sparks.
- for( int Loop = 0; Loop < kSparkCount; Loop++ )
- m_pSparks[ Loop ].Life = -1;
-
- // Default to normal mode
- m_bMissionMode = FALSE;
- m_Gravity = kNormalGravity;
-
- // Keep a black handy for erasing the sparks.
- rgb_color Black;
-
- Black.red = 0x00;
- Black.blue = 0x00;
- Black.green = 0x00;
- m_Black = index_for_color( Black );
- }
-
- DesktopView::~DesktopView()
- {
- kill_thread( ThreadId );
-
- if( m_pSparks )
- delete[] m_pSparks;
- }
-
- void DesktopView::AttachedToWindow()
- {
- srand( ( int ) __get_time() );
-
- m_pBitmap = new BBitmap( m_ScreenRect, B_COLOR_8_BIT, TRUE );
- m_pView = new BView( m_ScreenRect, "", 0, B_WILL_DRAW );
-
- m_pBitmap->Lock();
- m_pBitmap->AddChild( m_pView );
-
- // Erase the screen to black first.
- m_pView->SetHighColor( 0, 0, 0, 0 );
- m_pView->FillRect( m_ScreenRect );
- DrawBitmap( m_pBitmap, BPoint( 0, 0 ) );
-
- // draw it
- DrawOffscreen();
-
- m_pBitmap->Unlock();
-
- // We need to use this to call from the timer thread to this view
- pView = this;
-
- // We're gonna need an original mouse position.
- ulong TrashPoint;
- GetMouse( &m_OldMouse, &TrashPoint );
-
- ThreadId = spawn_thread( MyThread, "Timer Thread", B_DISPLAY_PRIORITY, NULL );
- resume_thread( ThreadId );
- }
-
- void DesktopView::Plot(long x, long y, char c)
- {
- char *p;
- long rowbyte;
-
- rowbyte = m_pBitmap->BytesPerRow();
-
- p = ( char * )m_pBitmap->Bits();
- if( y >= m_ScreenRect.top && x >= m_ScreenRect.left && x <= m_ScreenRect.right && y <= m_ScreenRect.bottom )
- {
- p += (y*rowbyte + x);
- *p = c;
- }
- }
-
- void DesktopView::Draw(BRect /*updateRect*/)
- {
- Window()->Lock();
- DrawBitmap(m_pBitmap, BPoint(0,0));
- Window()->Unlock();
- }
-
-
- void DesktopView::DrawOffscreen( )
- {
-
- Window()->Lock();
-
- m_pBitmap->Lock();
-
- // Used to find the bounding rectange of the sparks.
- int MinX = 16384;
- int MaxX = -1;
- int MinY = 16384;
- int MaxY = -1;
-
- int Loop;
- BPoint Point;
- ulong Button;
-
- GetMouse( &Point, &Button );
-
- if( m_bMissionMode )
- {
- Plot( m_MissionX, m_MissionY, m_Black );
- Plot( m_MissionX + 1, m_MissionY, m_Black );
- Plot( m_MissionX, m_MissionY + 1, m_Black );
- Plot( m_MissionX + 1, m_MissionY + 1, m_Black );
-
- m_MissionX++;
-
- if( m_MissionX >= m_ScreenRect.right )
- {
- m_bMissionMode = FALSE;
- m_Gravity = kNormalGravity;
- }
- }
-
- for( Loop = 0; Loop < kSparkCount; Loop++ )
- {
- // Check the bounding box....
- if( m_pSparks[ Loop ].x < MinX )
- MinX = m_pSparks[ Loop ].x;
- if( m_pSparks[ Loop ].x > MaxX )
- MaxX = m_pSparks[ Loop ].x;
- if( m_pSparks[ Loop ].y < MinY )
- MinY = m_pSparks[ Loop ].y;
- if( m_pSparks[ Loop ].y > MaxY )
- MaxY = m_pSparks[ Loop ].y;
-
- if( m_pSparks[ Loop ].Life > 0 ) // If the spark is currently alive, move it.....
- {
- // One day closer to death.
- m_pSparks[ Loop ].Life--;
-
- // Erase the previous dot
- Plot( m_pSparks[ Loop ].x, m_pSparks[ Loop ].y, m_Black );
-
- // Watch as the amazing gravity pulls upon our partical.
- m_pSparks[ Loop ].VerticalSpeed += m_Gravity;
-
- // Uncomment this to cause the sparks to bounce upon reaching the bottom of the screen.
- // if (m_pSparks[Loop].y + m_pSparks[Loop].VerticalSpeed > m_ScreenRect.bottom)
- // m_pSparks[Loop].VerticalSpeed = -m_pSparks[Loop].VerticalSpeed;
-
- // Update the sparks' position.
- m_pSparks[ Loop ].x += m_pSparks[ Loop ].HorizontalSpeed;
- m_pSparks[ Loop ].y += m_pSparks[ Loop ].VerticalSpeed;
-
- // Let's see it.
- Plot( m_pSparks[ Loop ].x, m_pSparks[ Loop ].y, m_pSparks[ Loop ].Color );
- }
- else // otherwise create a new one.
- {
- // Erase the last living incarnation of the spark
- Plot( m_pSparks[ Loop ].x, m_pSparks[ Loop ].y, m_Black );
-
- if( !m_bMissionMode )
- {
- // The cursor is my guide....
- m_pSparks[ Loop ].x = Point.x;
- m_pSparks[ Loop ].y = Point.y;
- }
- else
- {
- m_pSparks[ Loop ].x = m_MissionX;
- m_pSparks[ Loop ].y = m_MissionY;
- }
-
- // Gimme some random values to move this bad-boy along.
- m_pSparks[ Loop ].HorizontalSpeed = (rand()/32767.0)*kMaximumHorizontal-( kMaximumHorizontal/2.0 );
- m_pSparks[ Loop ].VerticalSpeed = -fabs( rand()/32768.0*kMaximumVertical );
-
- // Add the inertia factor...
- m_pSparks[ Loop ].HorizontalSpeed -= ( ( m_OldMouse.x - Point.x ) * kScalingFactor );
- m_pSparks[ Loop ].VerticalSpeed -= ( ( m_OldMouse.y - Point.y ) * kScalingFactor );
-
- m_pSparks[ Loop ].Life = abs( rand() % kLifeLength );
- m_pSparks[ Loop ].Color = rand() % 0xFF;
-
- }
- }
-
- m_pBitmap->Unlock();
-
- m_OldMouse = Point;
-
- // We only need to blit the maximum area changed,
- // with a generous fudge factor ( naturally ).
- m_BoundingRect.left = MinX - 2;
- m_BoundingRect.right = MaxX + 2;
- m_BoundingRect.top = MinY - 2;
- m_BoundingRect.bottom = MaxY + 2;
-
- DrawBitmap(m_pBitmap, m_BoundingRect, m_BoundingRect );
- Window()->Unlock();
- }
-
- void DesktopView::MouseDown( BPoint )
- {
- // Don't try it if we are already in "Impossible" mode.
- if( m_bMissionMode )
- return;
-
- BRect Rect;
-
- m_bMissionMode = TRUE;
- m_Gravity = kNoGravity;
-
- Window()->Lock();
- m_pBitmap->Lock();
-
- m_MissionX = m_ScreenRect.left;
- m_MissionY = ( m_ScreenRect.bottom - m_ScreenRect.top ) / 2.0; // Center the fuse
-
- // Erase all the old sparks before starting the fuse.
- m_pView->SetHighColor( 0, 0, 0, 0 );
- m_pView->FillRect( m_BoundingRect );
-
- m_pView->SetHighColor( 0xff, 0xff, 0xff );
- Rect.left = m_ScreenRect.left;
- Rect.top = m_MissionY;
- Rect.right = m_ScreenRect.right;
- Rect.bottom = m_MissionY;
- m_pView->FillRect( Rect );
-
- m_pView->Sync();
- m_pBitmap->Unlock();
-
- DrawBitmap( m_pBitmap, Rect, Rect );
-
- Window()->Unlock();
-
- }
-
- long MyThread( void * )
- {
- int Delay = 0;
-
- while( 1 )
- {
- snooze(20*1000.0);
- pView->DrawOffscreen();
- }
-
- return 0;
- }
-